//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Platforms/Base/IApplication.h"

#if defined( PLATFORM_WINDOWS )

#include "Platforms/Windows/WSensorManager.h"
#include "Platforms/Windows/WApplication.h"
#include "Base/Utils/Time/TimeProfiler.h"
#include "Graphics/GLES/opengles.h"


namespace Engine
{
namespace Platforms
{

	//
	// Windows Platform
	//

	class WindowsPlatform : public IPlatform
	{
	// types
	private:
		struct _Extensions
		{
			PFNWGLSWAPINTERVALEXTPROC			wglSwapInterval;
			PFNWGLGETSWAPINTERVALEXTPROC		wglGetSwapInterval;
			PFNWGLCHOOSEPIXELFORMATARBPROC		wglChoosePixelFormat;
			PFNWGLCREATECONTEXTATTRIBSARBPROC	wglCreateContextAttribs;
			bool								swapControlSupported;
			///
			_Extensions():
				wglSwapInterval(null), wglGetSwapInterval(null), wglChoosePixelFormat(null),
				wglCreateContextAttribs(null), swapControlSupported(false)
			{}
		};

		enum EPause
		{
			NO_FOCUS	= 0x1,
			USER_PAUSE	= 0x2,
			ON_DESTROY	= 0x4,
		};
		
		typedef static_array< string, EDirectory::_COUNT >	directories_t;


	// variables
	protected:
		WindowsSensorManager		_sensorManager;
		
		Ptr< IApplication >			_application;
		//WindowsHwCamera				_camera;

		_Extensions					_ext;
		
		directories_t				_directories;

		TimeProfiler<uint64>		_timer;
		
		winapi::HWND				_wnd;
		winapi::HDC					_dc;
		winapi::HGLRC				_rc;
		
		uint						_pause;

		ivec2						_windowSize;
		ivec2						_windowPos;
		SysEvent::time_t			_lastUpdateTime;

		bool						_isLooping;
		bool						_backgroundMode;
		bool						_terminated;

		EDevice::type				_requiredDeviceType;


		static WindowsPlatform *	_instance;


	// methods
	public:
		WindowsPlatform ();
		~WindowsPlatform ();

		virtual int  Loop ();

		virtual void SendEvent (const SysEvent &ev);
		virtual void SendEventDelayed (const SysEvent &ev);

		static Ptr< WindowsPlatform >	GetInstance ()			{ return _instance; }
		
		EDevice::type					GetDeviceType () const	{ return _requiredDeviceType; }

		static void CreateInstance ();
		static void DestroyInstance ();


	protected:
		// events //
		virtual bool _Init ();
		virtual void _Quit ();
		virtual void _EnterForeground (bool completed);
		virtual void _EnterBackground (bool completed);
		virtual void _VisibilityChanged (bool isVisible);
		virtual void _OnResized (uint w, uint h);
		virtual void _OnMove (const ivec2 &delta) {}
		
		virtual void _OnKey (int keyCode, bool down);
		virtual void _OnTouch (int id, bool down, int x, int y);
		virtual void _OnTouchMotion (int id, int x, int y);


	protected:
		SysEvent::time_t	_GetTimestamp ()	{ return _timer.GetTimeDelta(); }

		int  _ProcessMessage (UINT uMsg, WPARAM wParam, LPARAM lParam);
		bool _RegisterClass ();
		bool _CreateWindow ();
		bool _InitRawInput ();
		bool _InitOpenGL2 ();
		bool _InitOpenGL (INOUT VideoSettings &vs);
		void _Destroy ();

		void _Resize (ivec2 size);

		bool _EventLoop ();
		void _BackgroundLoop ();

		virtual void _Update (bool redraw);
		
		static LRESULT CALLBACK _MsgProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

		static uvec2		_GetScreenResolution ();

		static const char *	_GetClassName ()	{ return ENGINE_NAME; }
		static HMODULE		_GetInstance ()		{ return GetModuleHandle( (LPCSTR) null ); }


	// interface
	public:
		// Sensor //
		virtual bool EnableSensor (ESensor::type sensor) override						{ return _sensorManager.EnableSensor( sensor ); }
		virtual bool DisableSensor (ESensor::type sensor) override						{ return _sensorManager.DisableSensor( sensor ); }
		virtual bool IsSensorEnabled (ESensor::type sensor) override					{ return _sensorManager.IsSensorEnabled( sensor ); }
		virtual bool SetSensorUpdateRate (ESensor::type sensor, uint rate) override		{ return _sensorManager.SetSensorUpdateRate( sensor, rate ); }
		virtual bool HasSensor (ESensor::type sensor) override							{ return _sensorManager.HasSensor( sensor ); }

		// Render //
		virtual bool InitRender (INOUT VideoSettings &vs) override;
		virtual void SwapBuffers () override;
		virtual bool IsRenderingAvailable () override;
		
		// Audio //
		virtual void EnableAudio (bool enabled) override;
		
		// Extensions //
		virtual Ptr< HardwareCamera > GetCamera () override								{ return null; } //&_camera; }
		
		// License //
		virtual void CheckLicense (const OnLicenseChecked_t &callback, uni_c_string publicKey) override;

		// Other //
		virtual void Terminate () override;
		
		virtual void SendEmail (uni_c_string address, uni_c_string subject,
								uni_c_string text, uni_c_string attachment) override;
		
		virtual void Vibrate (const uni_array<const int64> &pattern) override {}

		//virtual void BackgroundMode (bool enabled) override;

		virtual void InitDevice (EDevice::type deviceType) override;
		virtual void SetDisplayOrientation (EDisplayOrientation::type orientation) override;
		
		virtual void OpenURL (uni_c_string url) override;

		virtual void ShowNotification (uni_c_string text, bool longTime) override;

		virtual void ShowMessage (const OnMessageResult_t &callback,
								  uni_c_string caption, uni_c_string text,
								  uni_c_string positive, uni_c_string negative) override;

		virtual EventSystemPtr		GetEventSystem () override;
		virtual IParallelThreadPtr	GetThread ()	  override;
		
		virtual uni_c_string 		GetDirectoryPath (EDirectory::type type) override	{ return _directories[ type ]; }
	};


}	// Platforms
}	// Engine

#endif	// PLATFORM_WINDOWS